package com.lyh.service.impl;

import com.lyh.mapper.TicketMapper;
import com.lyh.mapper.UserMapper;
import com.lyh.pojo.*;
import com.lyh.service.TicketService;
import com.lyh.utils.TackleDataUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.lang.reflect.Field;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Future;

@Service
public class TicketServiceImpl implements TicketService {

    @Autowired
    private UserMapper userMapper;

//    @Autowired
//    private TicketService ticketService;

    @Autowired
    private TicketMapper ticketMapper;

    @Autowired
    private ExecutorService executorService;

    //用于格式化日期
    private final SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");

    private final Logger logger = LoggerFactory.getLogger(this.getClass());

    @Override
    public Result<String> queryPageLoading(String from,  String to, String date, int count, String high, String precise) {
//
        Result<String> stringResult = new Result<>();

        CompletableFuture<Result<String>> ticketData = CompletableFuture.supplyAsync(() -> queryRoutesByStation(from, to, date, count, high, precise),executorService);
        CompletableFuture<Condition> conditionData = CompletableFuture.supplyAsync(() -> queryCondition(from, to, date),executorService);
        CompletableFuture<Map<String, Object>> mapCompletableFuture = conditionData.thenCombineAsync(ticketData, (r1, r2) -> {
            Map<String, Object> re = new HashMap<>();
//            System.out.println("--------------------------------------");
//            System.out.println(r1);
            re.put("condition", r2);
            re.put("ticket", r1);
//            System.out.println(r2);
//            System.out.println("--------------------------------------");
            return re;
        }, executorService);

        try {
            Map<String, Object> stringObjectMap = mapCompletableFuture.get();
            stringResult.setData(stringObjectMap);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }

        //串行执行
//        Result<String> stringResult1 = queryRoutesByStation(from, to, date, count, high, precise);
//        Condition stringResult2 = queryCondition(from, to, date);
//        stringResult.setMsg("串行查询");
//        Map<String,Object> map = new HashMap<>();
//        stringResult.setMsg("串行查询");
//        map.put("ticket",stringResult1);
//        map.put("condition",stringResult2);
//        stringResult.setData(map);


        return stringResult;
    }

    /**
     * 需要将
     * @param from 出发地
     * @param to 到达地
     * @param date 出发日期
     * @param count
     * @param high
     * @param precise
     * @return
     */
    @Override
    public Result<String> queryRoutesByStation( String from,  String to, String date, int count, String high, String precise) {
        logger.info("查询: from="+from+"  to="+to+"  date="+date);
        date = date.replace('-','_');
        String viaTable = "ado.t_via_" + date;
        String trainTable = "ado.t_train_" + date;

        Result<String> re = new Result<String>();
        List<Route> routes = null;
        int pageCount = 0;
        System.out.println("highSpeed = " + high);
        //如果不是指定类型, 就默认查询所有
        if(!"1".equals(high)&&!"0".equals(high)){
            high = " '0' , '1' ";
            System.out.println("修改后: highSpeed = " + high);
        }
        try {
            int totalCount;
            System.out.printf("查询车票: from=%s, to=%s, viaTable=%s, trainTable=%s \n", from, to, viaTable, trainTable);
            if("precise".equals(precise)){
                System.out.println("精确查询");
                totalCount = ticketMapper.queryRoutesCountPrecise(from, to, viaTable, trainTable, high);
            } else {
                System.out.println("模糊查询");
                totalCount = ticketMapper.queryRoutesCount(from, to, viaTable, trainTable, high);
            }
            System.out.println("记录条数为: "+ totalCount);

            //5条数据为一页, 如果有余数, 那么就会新开一页
            if(totalCount%5==0)
                pageCount = totalCount / 5;
            else
                pageCount = totalCount / 5 + 1;

            int firstRoute = count * 5 - 5;//起始
            int lastRoute = Math.min(totalCount, 5);
            //最后一条
            System.out.println("firstRoute = " + firstRoute);
            System.out.println("lastRoute:"+lastRoute);
            System.out.println("pageCount:"+ pageCount);
            //if(lastRoute > pageCount)
            //    lastRoute = pageCount - 1;
            //根据页数查询
            if("precise".equals(precise))
                routes = ticketMapper.queryRoutesByStationPrecise(from, to, viaTable, trainTable, firstRoute, lastRoute, high);
            else
                routes = ticketMapper.queryRoutesByStation(from, to, viaTable, trainTable, firstRoute, lastRoute, high);
            System.out.println("routes.size() = " + routes.size());
        } catch (Exception e) {
            logger.error("没有查询到 "+date+" 时间的火车票!");
            e.printStackTrace();
            //如果无法查询到结果就返回空
            return null;
        }
//        routes.stream()
        Future<?> task01 = executorService.submit(() -> {
        });
//        task01.

        //将train中座位转换未list
        for (Route route : routes) {
            Train train = route.getTrain();
            int trainId = train.getTrainId();
            List<Seat> list = new ArrayList<>();
            try {
                //通过getDeclaredFields()方法获取对象类中的所有属性（含私有）
                Field[] fields = train.getClass().getDeclaredFields();
                Seat seat = null;
                boolean isNotEmpty = false;
                for (int i=2;i<fields.length;i++) {
                    Field field = fields[i];
                    //设置允许通过反射访问私有变量
                    field.setAccessible(true);
                    //获取字段的值
                    //获取字段属性名称
                    String name = field.getName();
                    if(!name.contains("Price")){//座位类型属性
                        int value = 0;
                        try {
                            value = Integer.parseInt(field.get(train).toString());
                        } catch (IllegalArgumentException e) {
                            logger.error("数量值错误转换");
                        }
                        if(value!=0){
                            seat = new Seat();
                            seat.setType(name);
                            seat.setNumOfSeat(value+"");
                            isNotEmpty = true;
                        }
                    }else {//座位剩余数量属性
                        if(isNotEmpty){//如果这个座位的数量不是0, 才记录价格
                            String value = field.get(train).toString();
                            seat.setPrice(value);
                            seat.setSeatNo(trainId + seat.getType()+date);
                            list.add(seat);
                            isNotEmpty = false;
                        }
                    }
                }
                route.setSeatsList(list);
            } catch (Exception ex) {
                ex.printStackTrace();
                //处理异常
            }
        }


        System.out.println("记录总页数为: "+pageCount);
        re.setPageCount(pageCount);
        if(routes.size()==0)
            re.setData(null);
        else
            re.setData(routes);
        System.out.println("分页查询查询到的记录数为: "+routes.size());
        re.setMsg("查询的车票信息");

        return re;
    }

    @Override
    public Condition queryCondition(String from, String to, String date) {

        String table = date.replace('-','_');
        List<Route> routes = null;
        String viaTable = "t_via_"+table;
        String trainTable = "t_train_"+table;
        try {
            routes = ticketMapper.queryAllRoutesByStation(from, to, viaTable, trainTable);
        } catch (Exception e) {
            logger.error("没有查询到 "+date+" 时间的火车票!");
            return null;
        }

        List<String> fromStation = new ArrayList<>();
        List<String> toStation = new ArrayList<>();
        List<String> trainNum = new ArrayList<>();

        for (Route route : routes) {
            if(!fromStation.contains(route.getFrom()))
                fromStation.add(route.getFrom());

            if(!toStation.contains(route.getTo()))
                toStation.add(route.getTo());

            String num = route.getTrainNum().charAt(0)+"";
            if(!trainNum.contains(num))
                trainNum.add(num);
        }

        Condition condition = new Condition();


        condition.setFromStation(fromStation);
        condition.setToStation(toStation);
        condition.setTrainNum(trainNum);

        return condition;
    }

    
    
    /**
     *
     * @param no 车票号格式: train_id/via_id + 座位类型 + 时间
     * @param userId 用户id
     */
    @Override
    @Transactional(timeout = 5)
    public Result<String> purchaseTicket(String no,String userId) {
        System.out.println("购买的车票号为: "+no);
        Result<String> result = new Result<>();
        HashMap<String, String> params = new HashMap<>();

        //先查看垓用户是否存在未支付的订单, 如果是就直接返回false
        params.put("userId",userId);
        if(ticketMapper.checkUnpaidOrder(params)>0){
            result.setFlag(false);
            result.setMsg("该用户还有未支付订单,无法购买!");
            result.setErrorType(0);
            return result;
        }

        //解析no获取相关的列车票信息
        int len = no.length();
        int trainId = 0;
        int i = 0;//记录前面数值的位数
        //将字符的变成数字, 数字过后是字母(座位类型), 字母是不在0到10之间的
        for(;i<len;i++){
            int n = 0;
            n = Character.getNumericValue(no.charAt(i));//将字符变为数值
            if(n<0||n>=10)
                break;
            if(trainId!=0)
                trainId*=10;
            trainId+=n;
        }

        //座位种类
        String seatType = no.substring(i, len - 10);
        //日期
        String date = no.substring(len - 10, len);
        String trainTable = "t_train_"+date;
        String viaTable = "t_via_"+date;

        params.put(seatType,seatType);//只是判断key而已
        params.put("trainTable",trainTable);
        params.put("viaTable",viaTable);
        params.put("trainId",trainId+"");//用于查询座位
        params.put("viaId",trainId+"");//用于创建订单
        params.put("seatType",seatType);
        params.put(seatType+"Price",seatType);
        //日期格式字符替换
        String date_v = date.replaceAll("_","-");
        params.put("date",date_v);

        //获得剩余座位个数
        Seat seatFromDB = ticketMapper.checkSeat(params);
        seatFromDB.setType(seatType);
        int num = Integer.parseInt(seatFromDB.getNumOfSeat());

        Ticket ticket = null;
        if(num>0){
            num--;
            params.put(seatType,num+"");
            String time = sdf.format(new Date());//将现在的时间格式化
            params.put("purchaseTime",time);
            params.put("seatNum",seatFromDB.getNumOfSeat());
            params.put("price",seatFromDB.getPrice());
            params.put("status","1");
            //减一个座位
            ticketMapper.updateSeatLeft(params);

            //创订单
            ticketMapper.createOrder(params);

            //找出一张票的可查询出的信息
            ticket = ticketMapper.queryTicketInfoById(params);

            //补充票的信息
            ticket.setPrice(Double.parseDouble(seatFromDB.getPrice()));
            ticket.setSeatNo(Integer.parseInt(seatFromDB.getNumOfSeat()));
            ticket.setDate(date_v);
            ticket.setTradeCode(trainId+seatType+date);//设置交易码
            ticket.setPaidStatus(1);

            //将完整的票存放到数据库中
            ticketMapper.createTicket(ticket);

            result.setFlag(true);
            result.setMsg("已创建好未支付订单!");
            result.setData(ticket);
            return result;
        }else {
            //如果没有余票,返回null
            result.setFlag(false);
            result.setMsg("该车票已售空!");
            result.setErrorType(2);
            return result;
        }
    }

    @Override
    public Result<String> pay(String orderId) {
        Result<String> result = new Result<>();
        int id = Integer.parseInt(orderId);
        int i = ticketMapper.checkOrder(id);
        if(i == 1){
            ticketMapper.payOrder(id);
            ticketMapper.payTicket(id);
            result.setFlag(true);
            result.setMsg("支付成功!");
        } else if (i == 2){
            result.setFlag(false);
            result.setMsg("该订单已支付!");
        } else {
            result.setFlag(false);
            result.setMsg("该订单已取消或已过期!");
        }

        return result;
    }

    @Override
    public Result<Ticket> queryTicket(Integer userId,int paidStatus) {
        //当前paidStatus 0未支付 1已支付 2全部 3已退款 4已完成 已过期
        //数据库中0已退款 1预定未付款 2预定已付款 3已经过期
        Result<Ticket> result = new Result<>();
        //直接查询sql, 看看是否有内容, 如果没有内容就说明没有订单
        int status = 0;
        List<Integer> paidList;
        if(paidStatus!=2){ //查询指定状态的票
            switch (paidStatus){
                case 0: status = 1; break;
                case 1: status = 2; break;
                case 3: status = 0; break;
                case 4: status = 3; break;
            }
            paidList =  ticketMapper.queryOrderByUserId(userId, status);//只返回orderId
        }else//查询所有票
            paidList = ticketMapper.queryAllOrderByUserId(userId);

        if(paidList.size() > 0){
            List<Ticket> tickets = ticketMapper.getTicketsByOrderId(paidList);
            //搜索该用户的手机号码
            User user = userMapper.queryUserByUserId(userId);
            //加密手机号
            String phone = TackleDataUtils.phone(user.getPhone());

            for (Ticket ticket : tickets) {
                ticket.setPhone(phone);
                ticket.setTradeCode(ticket.getViaId()+ticket.getSeatType()+ticket.getDate());
                //座位翻译 英文变成中文
                ticket.setSeatType(TackleDataUtils.translateSeatType(ticket.getSeatType()));
            }
            result.setResultList(tickets);//将未支付订单数据装入
            result.setFlag(true);
            return result;
        }else {
            result.setFlag(false);
            switch (paidStatus){
                //并没有使用到信息
                case 0: result.setMsg("您还没有未支付的订单!"); break;
                case 1: result.setMsg("您没有已支付的订单!"); break;
                case 2: result.setMsg("您还没有订单!"); break;
            }
            return result;
        }
    }

    @Override
    @Transactional(timeout = 5)
    public int refund(Integer userId, int orderId) {

        /**
         * 实现步骤:
         * 1.想查询是否有相应的order的payStatus 根据userId跟orderId查询
         * 2.有, 根据orderId, 查询相应的列车位置, 加上1, 然后删除order跟ticket
         * 3.没有, 直接返回消息
         */
        Order order = ticketMapper.queryOrderByUidAndOid(orderId,userId);
        if(order==null){
            return 2;//查询没有相应订单
        }

        int status = order.getStatus();

        if(status==3)
            return 3;
        //如果不为3就检测是否需要变为3
        Date viaDate = order.getViaDate();
        Date currentTime = new Date();
        if(viaDate.before(currentTime)){
            //如果购买的车票时间是在当前时间之前的, 就说明已经过期了
            if(order.getStatus()!=3){
                //当票的状态不是过期状态的时候更新为过期
                ticketMapper.outdateOrder(orderId);
                ticketMapper.outdateTicket(orderId);
            }
            return 3;
        }


        switch (status){
            case 0: return 4;//已退款
            case 1: return 5;//未付款
            case 2:
                String seatType = TackleDataUtils.changeSeatType(order.getSeatType());
                String date = sdf.format(order.getViaDate()).replace('-','_');
                //票正常, 可以退款

                //1.先将座位数量复原
                ticketMapper.recoverSeat("t_train_"+date,order.getViaId(),seatType);

                //2.修改订单消息为已退款状态
                ticketMapper.refundOrder(orderId, userId);
                //3.删除列车票消息
                ticketMapper.refundTicket(orderId);
                break;
        }
        return 1;//正常退款
    }

    @Override
    @Transactional(timeout = 5)
    public int cancel(Integer userId, int orderId) {
        Order order = ticketMapper.queryOrderByUidAndOid(orderId, userId);
        if (order==null)
            return 1;//返回订单不存在

        String date = sdf.format(order.getViaDate()).replace('-','_');
        String seatType = TackleDataUtils.changeSeatType(order.getSeatType());
        //0.先将座位数量复原
        ticketMapper.recoverSeat("t_train_"+date,order.getViaId(),seatType);

        //1.取消ticket
        ticketMapper.deleteTicket(orderId);
        //2.取消order
        ticketMapper.deleteOrder(orderId);

        return 0;
    }

}
